<HEAD>
	<title>Implementation notes</title>
	<META http-equiv="Content-Type" content="text/html; charset=windows-1252">
</HEAD>
<BODY>
	<meta http-equiv="Content-Language" content="en-us">
	<link rel="stylesheet" type="text/css" href="Meta.css">
		<H1 id="heading0"><SPAN>Implementation notes</SPAN></H1>
		<P><SPAN>Release 1.3, March 2006</SPAN><BR>
			<SPAN>Ian Horswill, Northwestern 
University</SPAN></P>
		<P><SPAN>The canonical version of this file is on the Animate Arts Wiki: 
http://dada.cs.northwestern.edu.</SPAN></P>
		<H2><SPAN>Contents</SPAN></H2>
		<UL>
			<LI>
				<A title="External web link to file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Design_decisions"
					href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Design_decisions">
					<A href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Design_decisions">
						<SPAN style="TEXT-DECORATION: underline">Design decisions</SPAN></A></A>
			<LI>
				<A title="External web link to file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Code_execution"
					href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Code_execution">
					<A href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Code_execution">
						<SPAN style="TEXT-DECORATION: underline">Code execution</SPAN></A></A>
			<LI>
				<A title="External web link to file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Parsers"
					href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Parsers">
					<A href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Parsers">
						<SPAN style="TEXT-DECORATION: underline">Parsing</SPAN></A></A>
			<LI>
				<A title="External web link to file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#DLL_loading"
					href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#DLL_loading">
					<A href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#DLL_loading">
						<SPAN style="TEXT-DECORATION: underline">DLL loading</SPAN></A></A>
			<LI>
				<A title="External web link to file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Type_lattice"
					href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Type_lattice">
					<A href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Type_lattice">
						<SPAN style="TEXT-DECORATION: underline">Type lattice and generic 
  operations</SPAN></A></A>
			<LI>
				<A title="External web link to file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Bugs_and_misfeatures"
					href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Bugs_and_misfeatures">
					<A href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Bugs_and_misfeatures">
						<SPAN style="TEXT-DECORATION: underline">Bugs and misfeatures</SPAN></A></A></LI></UL>
		<P><SPAN>Note: while not entirely incomprehensible to non-specialists, these 
notes assume a fair amount of familiarity with functional languages and language 
implementation.</SPAN></P>
		<H2 id="heading1"><A title="External web link to " href=""><A><SPAN>Design 
decisions</SPAN></A></A></H2>
		<P><SPAN>Meta was designed with the following priorities in mind:</SPAN></P>
		<OL>
			<LI>
				<SPAN style="FONT-WEIGHT: bold">Provide a good scripting-like language for 
  first-time programmers.</SPAN><BR>
				<SPAN>Consequently, the focus in the 
  language was on expressivity and elegance. The focus in the implementation was 
  on debugability and interoperability with existing code bases, rather than on 
  performance. </SPAN>
			<LI>
				<SPAN style="FONT-WEIGHT: bold">Be a "real" language in the sense that you 
  could write a large program in it if you wanted 
  to.</SPAN><BR>
				<SPAN>Consequently, we didn't deliberately neuter the language 
  or add the kinds of special-case syntactic sugar that is common in some 
  scripting languages. </SPAN>
			<LI>
				<SPAN style="FONT-WEIGHT: bold">Avoid traumatizing first-time programmers 
  any more than necessary.</SPAN><BR>
				<SPAN>Consequently, we tried to avoid 
  assulting the user with information they wouldn't necessarily understand. We 
  also avoid certain things that hang up beginning programmers like dotted-pair 
  notation. We also start students off with tail-call optimization turned off so 
  that the debug stack accurately reflects the series calls that lead to the 
  current failure. </SPAN>
			<LI>
				<SPAN style="FONT-WEIGHT: bold">Make the programming environment 
  "prettier" and less nerdly.</SPAN><BR>
				<SPAN>I don't know how successful this 
  has been, but the idea was to not have beginning programmers start with an IDE 
  that was optimized for fixed-width fonts and maximum presentation of 
  information, most of which the students wouldn't understand anyway. 
  </SPAN></LI></OL>
		<H2 id="heading2"><SPAN>Implementation strategy</SPAN></H2>
		<H3 id="heading3"><SPAN>Interpreter</SPAN></H3>
		<P><SPAN>As of this writing, Meta is implemented in three languages: C#, a macro 
language that expands to C#, and Meta itself. The macro processor is essentially 
C# with Scheme syntax, a macro system, and type inference. It's designed to be 
just good enough to compile the interpreter and primops (primitive procedures), 
but isn't otherwise really ready for prime time. It's main purpose is to hide a 
lot of design decisions, such as the layout and protocol of procedure objects, 
behind a set of macros so that I can experiment with different implementation 
strategies w/o having to do wholesale rewrites of all the primops.</SPAN></P>
		<H3 id="heading4"><SPAN>C# extensions</SPAN></H3>
		<P><SPAN>The macro processor is very limited. For example, it doesn't really 
understand overloading or constructor inheritance, and it doesn't have any 
automated way of importing type definitions for the CLR framework classes. 
Consequently, code which requires the use of more essoteric C# features, is 
written directly in C#.</SPAN></P>
		<H3 id="heading5"><SPAN>Compiler</SPAN></H3>
		<P><SPAN>More recently, Meta has gotten to the point where its practical to 
write chunks of it in Meta itself, particularly macros which are a pain to write 
in C#. However, since Meta is an interpreted language, there has to be some 
mechanism for loading the Meta code into the run-time environment at startup 
time. Initially, this was done by having a very large string constant embedded 
in a C# file. This worked just fine and I probably should have stuck with it, 
but I found it too annoyingly ugly. An alternative would have been to serialize 
the ASTs used by the interpreter, store that someplace, and then deserialize 
them. In the end, I wrote a simplistic native code compiler that does a very 
simplistic translation of Meta code to method calls. It's not clear that in the 
end this is any faster than the interpreted code, but it makes for a nice piece 
of example code and one day, I'll put some actually analysis and optimization 
into it. Note, however, that the compiler, like the macro processor, is really 
only designed to be good enough to compile Meta itself, and there are a number 
of basic things that it just doesn't do. User code should almost always be 
interpreted.</SPAN></P>
		<H1 id="heading6"><A title="External web link to " href=""><A><SPAN>Code 
execution</SPAN></A><IMG src="images/external-link.gif" border="0"></H1>
		<H2 id="heading7"><A title="External web link to " href=""><A><SPAN>Expressions 
and evaluation</SPAN></A><IMG src="images/external-link.gif" border="0"></A></H2>
		<P><SPAN>Code in Meta is first read as a series of (plain-text) characters, 
which are parsed by a fairly standard lisp-like reader into generalized lists, 
i.e. s-expressions. The s-expressions and then transformed into Expression 
objects (CLR type Meta.Expression) by "</SPAN><A title="External web link to file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Parsers"
				href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Parsers"><A href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Parsers"><SPAN style="TEXT-DECORATION: underline">parsers</SPAN></A></A><SPAN>" (type 
Meta.Parser), and then executed by the interpreter.</SPAN></P>
		<P><SPAN>The Expression class has subclasses for all the core syntactic forms: 
global and local variables, applications, conditionals, assignments, lambdas, 
etc. The principle methods on Expressions are Eval, which forms the core of the 
interpreter, and unparse, which regenerates an s-expression form for the 
expression. Unparse is largely used by the debugger.</SPAN></P>
		<P><SPAN>Expressions also have a property list (for future use by compilers), 
and a simplify method, which is used to do small amounts of optimization, and 
also to link each Expression to its parent Expression, if any.</SPAN></P>
		<P><SPAN>Other than the </SPAN><A title="External web link to file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#evaluation-stack"
				href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#evaluation-stack"><A href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#evaluation-stack"><SPAN style="TEXT-DECORATION: underline">EvalStack</SPAN></A></A><SPAN>, the only 
thing particularly baroque about the interpreter is the proliferation of 
subclasses of Application. This allows a little bit of static analysis, mostly 
to reduce unnecessary memory allocation:</SPAN></P>
		<UL>
			<LI>
				<SPAN>The default type used to represent a procedure call is 
  ApplicationGeneral, which calls its function object using Apply. </SPAN>
			<LI>
				<SPAN>If the call is to a GlobalVariable, which is bound to a </SPAN><A title="External web link to file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Calling_sequences"
					href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Calling_sequences"><A href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Calling_sequences"><SPAN style="TEXT-DECORATION: underline">CallInterfaceProcedure</SPAN></A></A><SPAN>, 
  is marked as a constant, and has 10 or fewer arguments, the parser will choose 
  a specialized representation: Application1, Application2, etc., depending on 
  the number of arguments. These classes call their targets with Call and do not 
  cons a list to hold the arguments. </SPAN>
			<LI>
				<SPAN>If the call is in tail position and isn't to a global constant 
  </SPAN><A title="External web link to file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Calling_sequences"
					href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Calling_sequences"><A href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Calling_sequences"><SPAN style="TEXT-DECORATION: underline">CallInterfaceProcedure</SPAN></A></A><SPAN>, 
  the system will represent the call as a TailCall object. TailCalls do not call 
  their targets, but instead rewrite the current </SPAN><A title="External web link to file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#evaluation-stack"
					href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#evaluation-stack"><A href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#evaluation-stack"><SPAN style="TEXT-DECORATION: underline">EvalStack</SPAN></A></A><SPAN> frame and 
  return a special token which is recognized by the InterpretedProcedure's 
  </SPAN><A title="External web link to file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Tail_call_optimization"
					href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Tail_call_optimization"><A href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Tail_call_optimization"><SPAN style="TEXT-DECORATION: underline">trampoline</SPAN></A></A><SPAN>. 
  </SPAN></LI></UL>
		<H2 id="heading8"><SPAN>Procedures</SPAN></H2>
		<P><SPAN>Meta procedures are implemented as a special class rather than as 
delegates. This was partly for efficiency reasons and partly to improve 
debugability, since it allows us to generate our own error messages for things 
like calls with the wrong number of arguments.</SPAN></P>
		<P><SPAN>Procedures are called using the TracedCall() and TracedApply methods, 
which are not virtual. These then call into the (virtual) Call and Apply 
methods, which are where the specialization for different kinds of procedures 
should take place. Both Call() and TracedCall() are overloaded for 0-20 
arguments of type object. Apply takes an Object[] argument. All of these methods 
are overloaded to take an optional </SPAN><A title="External web link to file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#evaluation-stack"
				href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#evaluation-stack"><A href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#evaluation-stack"><SPAN style="TEXT-DECORATION: underline">EvalStack</SPAN></A></A><SPAN> argument for 
</SPAN><A title="External web link to file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#evaluation-stack"
				href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#evaluation-stack"><A href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#evaluation-stack"><SPAN style="TEXT-DECORATION: underline">efficiency 
reasons</SPAN></A></A><SPAN>.</SPAN></P>
		<P><SPAN>There is also a special TailApply() entry point which is only used for 
interpreted procedures calling into other interpreted procedures.</SPAN></P>
		<H3 id="heading9"><A title="External web link to " href=""><A><SPAN>Calling 
sequences</SPAN></A></A></H3>
		<P><SPAN>The two main subclasses of Meta.Procedure are 
Meta.CallInterfaceProcedure and Meta.ApplyInterface procedure. Each provides a 
set of default implementations for all the Call and Apply methods so that a user 
defining a new Procedure class need only overload one method.</SPAN></P>
		<P><SPAN>The CallInterfaceProcedure provides an Apply implementation that 
unpacks the arguments from the list and calls into the appropriate Call method. 
All Call methods throw ArgumentCountExceptions by default, so the user need only 
provide a single Call method, and that method need not check the argument 
count.</SPAN></P>
		<P><SPAN>Conversely, the ApplyInterfaceProcedure provides Call methods that 
redirect into the Apply method. The user then need only define Apply.</SPAN></P>
		<H3 id="heading10"><SPAN>Delegates</SPAN></H3>
		<P><SPAN>The Meta.DelegateGenerator class is responsible for dynamically 
compiling types to serve as wrapper classes for Meta procedures. When the 
AsDelegate(Type) method is called on a Meta procedure, it calls the AsDelegate 
static method of DelegateGenerator, which looks up or creates the appropriate 
wrapper class and creates the appropriate delegate.</SPAN></P>
		<H3 id="heading11"><SPAN>InterpretedProcedures</SPAN></H3>
		<P><SPAN>The InterpretedProcedure class is an ApplyInterfaceProcedure that 
contains an argument list and body. When Apply'ed, it creates an Environment 
object from the argument list and evals the body. The Apply method also contains 
a </SPAN><A title="External web link to file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Tail_call_optimization"
				href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Tail_call_optimization"><A href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Tail_call_optimization"><SPAN style="TEXT-DECORATION: underline">trampoline loop</SPAN></A></A><SPAN>, to 
handle tail calls.</SPAN></P>
		<H3 id="heading12"><SPAN>Compiled procedures</SPAN></H3>
		<P><SPAN>The present compiler produces procedures that use the Apply calling 
sequence rather than direct calls. This was easiest, if slowest, way to 
implement lexical scoping. There is no environment analysis to determine when 
the native CLR stack can be used instead. This probably won't change until 
version 2.0 of the CLR is release, which is supposed to have native support for 
closures. </SPAN></P>
		<H2 id="heading13"><A title="External web link to " href=""><A><SPAN>The 
evaluation stack</SPAN></A></A></H2>
		<P><SPAN>In order to ensure that the debugger can recover the arguments to all 
meta procedure calls after an exception or breakpoint, the interpreter maintains 
a shadow stack, called the EvalStack, which holds the procedure, arguments, and 
local environment of every pending Meta procedure. As of release 1.1, the system 
automatically allocates EvalStacks for threads on demands, so that any thread 
can safely call code written in Meta.</SPAN></P>
		<P><SPAN>A lot of work has gone into optimizing the EvalStack:</SPAN></P>
		<UL>
			<LI>
				<SPAN>The stack is stored in parallel arrays rather than an array of frame 
  objects, so as to minimize load on the garbage collector. </SPAN>
			<LI>
				<SPAN>Separate representations are used for Meta procedures that take 
  their arguments as separate CLR arguments (i.e. </SPAN><A title="External web link to file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Calling_sequences"
					href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Calling_sequences"><A href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Calling_sequences"><SPAN style="TEXT-DECORATION: underline">CallInterfaceProcedures</SPAN></A></A><SPAN>) 
  rather than as a single list. Arguments for the former are pushed onto yet 
  another big array, so that the argument pointer in the main EvalStack can just 
  point into the array. This avoids allocating an unnecessary list object. 
  </SPAN>
			<LI>
				<SPAN>Looking up the EvalStack in thread-local storage and creating it if 
  necessary is </SPAN><SPAN style="FONT-STYLE: italic">extremely 
  </SPAN><SPAN>expensive, so the interpreter actually passes the current 
  EvalStack as an explicit parameter to every method in the interpreter so we 
  only have to look it up once. I know this sounds crazy, but it cuts total 
  execution time by about 70%. </SPAN></LI></UL>
		<H2 id="heading14"><A title="External web link to " href=""><A><SPAN>Tail-call 
optimization</SPAN></A></A></H2>
		<P><SPAN style="FONT-WEIGHT: bold">N.B.: </SPAN><SPAN>Users should not rely on 
the tail-call interface being stable, since it will probably change if and when 
we can get rid of the EvalStack. User code should therefore avoid calling 
TailApply().</SPAN></P>
		<P><SPAN>The interpreter only optimizes tail calls from interpreted code. At 
present, there's no support for allowing primops to call tail-recursively back 
into interpreted code.</SPAN></P>
		<P><SPAN>Tail calls are </SPAN><A title="External web link to file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#tail-call-recognition"
				href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#tail-call-recognition"><A href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#tail-call-recognition"><SPAN style="TEXT-DECORATION: underline">recognized statically</SPAN></A></A><SPAN>. The Eval() method of the 
TailCall class (a subclass of </SPAN><A title="External web link to file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Expressions_and_evaluation"
				href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Expressions_and_evaluation"><A href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Expressions_and_evaluation"><SPAN style="TEXT-DECORATION: underline">Expression</SPAN></A></A><SPAN>) evaluates the call's 
function and arguments, then rewrites the current </SPAN><A title="External web link to file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#evaluation-stack"
				href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#evaluation-stack"><A href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#evaluation-stack"><SPAN style="TEXT-DECORATION: underline">EvalStack</SPAN></A></A><SPAN> frame to reflect the new 
procedure and arguments, and returns the magic object 
TailCallCookie.theTailCallCookie.</SPAN></P>
		<P><SPAN>Tail calls are handled by a "trampoline loop" in the Apply method of 
class InterpretedProcedure. This calls the Eval method of the procedure's body 
and checks whether the return value is the magic tail call cookie. If so, it 
pulls the procedure and argument list from the current EvalStack frame and calls 
the procedure's TailApply method. For normal procedures, the TailApply method 
falls through to the normal Apply method. For InterpretedProcedures, the 
TailApply method is the same as the normal Apply method, except it doesn't 
include a trampoline loop. Any tail calls it makes will therefore fall through 
to the original procedure's trampoline loop, which is still active. The process 
repeats until something something returns a real value, either because an 
interpreted procedure returns a constant or variable value, or because it 
tail-calls a primop.</SPAN></P>
		<H2 id="heading15"><SPAN>Object member access</SPAN></H2>
		<P><SPAN>Member expressions, which are the long form for which the X.Y notation 
is syntactic sugar, are parsed into different Expression classes, depending on 
whether they're used as a member reference, assignment, or method invocation. 
Namespace references (e.g. System.Drawing.foo or Packages.Compiler.foo) are not 
represented as expressions per se, but are resolved during the parsing process 
(see </SPAN><A title="External web link to file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Namespaces"
				href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Namespaces"><A href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Namespaces"><SPAN style="TEXT-DECORATION: underline">namespaces</SPAN></A></A><SPAN>).</SPAN></P>
		<P><SPAN>Internally, each member expression is implemented using a 
MemberAccessor object, which looks up the appropriate member and performs the 
appropriate action. This is more efficient than just going through the 
InvokeMember interface of the reflection API because we can cache the member 
lookup. In the case of member references (not assignments or calls) for methods, 
it wraps the method to make it look like a normal Meta procedure. Different 
wrapper classes (all of which are subclasses of </SPAN><A title="External web link to file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Calling_sequences"
				href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Calling_sequences"><A href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Calling_sequences"><SPAN style="TEXT-DECORATION: underline">ApplyInterfaceProcedure</SPAN></A></A><SPAN>) are used depending on 
whether the reference is a static or instance member, and on whether it is 
overloaded:</SPAN></P>
		<UL>
			<LI>
				<SPAN>References to unoverloaded instance methods of types are wrapped by 
  class MethodWrapper. For example, an expression like: [map Object.ToString 
  list] will evaluate to a MethodWrapper object. MethodWrappers use the Invoke 
  method of the MethodInfo object. </SPAN>
			<LI>
				<SPAN>References to unoverloaded instance methods of objects are wrapped 
  by class ClosedMethodWrapper. ClosedMethodWrapper also using the Invoke method 
  of MethodInfo object, but store the object to which to apply the method in the 
  wrapper itself (i.e. the method is closed over the object). </SPAN>
			<LI>
				<SPAN>References to unoverloaded static methods are also wrapped by 
  ClosedMethodWrappers. </SPAN>
			<LI>
				<SPAN>References to overloaded methods are wrapped by 
  ClosedAmbiguousMethodWrapper and ClosedAmbiguousStaticMethodWrapper, 
  respecitively, which use Type.InvokeMember instead of MethodInfo.Invoke, i.e. 
  they look up the method every time. </SPAN></LI></UL>
		<P><SPAN>Similarly, events are wrapped with objects that support Add, Remove, 
and Invoke methods. As a convenience feature, assigning to an event member is 
treated as an Add call. When adding a Meta procedure as an event handler, the 
system automatically coerces into the appropriate delegate type.</SPAN></P>
		<H2 id="heading16"><SPAN>Generic procedures</SPAN></H2>
		<P><SPAN>Generic procedures are presently implemented as </SPAN><A title="External web link to file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Calling_sequences"
				href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Calling_sequences"><A href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#Calling_sequences"><SPAN style="TEXT-DECORATION: underline">ApplyInterfaceProcedures</SPAN></A></A><SPAN> containing a sorted list of 
Meta.GenericProcedure.Method objects, each containing a signature and a 
procedure to call. Methods are sorted from most specific to least specific. 
Decision trees would be much faster, but generic procedures aren't used very 
heavily right now.</SPAN></P>
		<H2 id="heading17"><SPAN>Fluids</SPAN></H2>
		<P><SPAN>All names in Meta are lexically scoped. Dynamic scoping is implemented 
through fluids (CLR class Meta.Fluid), which are presented to the programmer as 
thunks (parameterless procedures) that return the current value assigned to the 
fluid. Fluids can be assigned using the normal assignment operator or locally 
bound using the bind procedure.</SPAN></P>
		<P><SPAN>The current implementation uses deep binding, meaning the fluid system 
maintains a per-thread stack of fluid bindings and searches the stack for the 
latest binding to find a fluid's current value. Although the C# programmer can, 
in theory, get the current value of a fluid by calling its Call method (since 
it's a Meta procedure), the Fluid class also exports a read/write Value 
property, which is more convenient to use from C#.</SPAN></P>
		<P><SPAN>Adding new bindings to the fluid stack is much more of a pain to do 
from C#, however, since this requires constructing a delegate for the operation 
to be performed while the binding is in effect. The format of the call to add a 
temporary binding to a fluid is:</SPAN><BR>
			<BR>
			<SPAN style="FONT-STYLE: italic">result</SPAN><SPAN> = Fluid.Bind(new object[] { 
</SPAN><SPAN style="FONT-STYLE: italic">theFluid</SPAN><SPAN>, </SPAN><SPAN style="FONT-STYLE: italic">newValue</SPAN><SPAN> }, new Meta.Thunk(</SPAN><SPAN style="FONT-STYLE: italic">method</SPAN><SPAN>));</SPAN><BR>
			<BR>
			<SPAN style="FONT-STYLE: italic">TheFluid</SPAN><SPAN> can be any fluid and 
</SPAN><SPAN style="FONT-STYLE: italic">newValue</SPAN><SPAN>, any object you 
wish to assign to it. </SPAN><SPAN style="FONT-STYLE: italic">Method</SPAN><SPAN> should be parameterless method 
that returns a System.Object. Bind can also be used to bind several fluids at 
once, as in:</SPAN><BR>
			<BR>
			<SPAN style="FONT-STYLE: italic">result</SPAN><SPAN> 
= Fluid.Bind(new object[] { </SPAN><SPAN style="FONT-STYLE: italic">fluid</SPAN><SPAN>1 , </SPAN><SPAN style="FONT-STYLE: italic">value</SPAN><SPAN>1 ,</SPAN><SPAN style="FONT-STYLE: italic"> fluid</SPAN><SPAN>2 , </SPAN><SPAN style="FONT-STYLE: italic">value</SPAN><SPAN>2 , ... }, new 
Meta.Thunk(</SPAN><SPAN style="FONT-STYLE: italic">method</SPAN><SPAN>));</SPAN><BR>
			<BR>
			<SPAN>Threads 
begin with an empty binding stack unless they are created with Meta's spawn 
primitive, in which case they inherit the calling thread's binding 
stack.</SPAN></P>
		<H1 id="heading18"><A title="External web link to " href=""><A><SPAN>Parsing</SPAN></A></A></H1>
		<P><SPAN>Reading of s-expressions is implemented by the class Meta.Reader, which 
takes a TextReader as its constructor argument. Its principle method is 
Read().</SPAN></P>
		<P><SPAN>As mentioned before, s-expressions are transformed into Expression 
objects, the abstract syntax trees used by the interpreter, by parsers, which 
are objects of class Meta.Parser and its associated subclasses. The main 
entry-point to parsers is the Parse(object exp, Parser subparser) method. The 
subparser is the parser object to which the parser should delegate expressions 
it doesn't recognize.</SPAN></P>
		<P><SPAN>Parsers are used for </SPAN><SPAN style="FONT-STYLE: italic">all</SPAN><SPAN> mapping of s-expressions to 
Expressions. This turns out to be a wide range of different tasks, and so there 
are several different flavors of parser:</SPAN></P>
		<H2 id="heading19"><SPAN>The Parser class</SPAN></H2>
		<P><SPAN>The Parse method of the base Parser class performs the main case 
analysis for parsing:</SPAN></P>
		<UL>
			<LI>
				<SPAN>If the s-expression is already an Expression object, it is returned. 
  </SPAN>
			<LI>
				<SPAN>If the expression is a symbol, it calls the parser's Lookup method. 
  </SPAN>
			<LI>
				<SPAN>If the expresssion is any other atom, it creates a Constant 
  expression. </SPAN>
			<LI>
				<SPAN>If the expression is a list containing the symbol &#8594; and whose first 
  element is not the quote symbol, the parser returns a LambdaExpression </SPAN>
			<LI>
				<SPAN>If the expression is a list whose second element is the &#8592; symbol is 
  whose first element is not the quote symbol, the parser returns an 
  AssignmentExpression object. </SPAN>
			<LI>
				<SPAN>If the expression is a list whose first element is a global variable 
  bound to a parser object, the expression is a macro call or special form. The 
  method calls the new parser's Parse method, passing it the s-expression and 
  the old parser as arguments. </SPAN>
			<LI>
				<SPAN>Otherwise, the expression is an application: </SPAN></LI>
			<UL>
				<LI>
					<SPAN>If the first element of the list denotes a global variable bound 
    to a constant that is a CallInterfaceProcedure, the parser generates a 
    specialized Application1, Application2, etc. object </SPAN>
				<LI>
					<SPAN>Otherwise the parser generates a ApplicationGeneral object 
    </SPAN></LI></UL>
		</UL>
		<H2 id="heading20"><SPAN>Special forms</SPAN></H2>
		<P><SPAN>For each special form (begin, with, etc.), there is a specialized 
parser object that knows how to parse that form and a binding in the root 
namespace to its respective parser object.</SPAN></P>
		<H2 id="heading21"><SPAN>Macros</SPAN></H2>
		<P><SPAN>Macros are implemented by the Meta.Macro class, which is a subclass of 
the Parser class containing a rewrite-procedure field, which holds a Meta 
procedure object. When the Macro's Parse method is called, it calls the meta 
procedure with the s-expression. The procedure can either return an Expression 
object or a new s-expression. In the latter case, the macro calls the 
subparser's Parse method on the new s-expression and returns the 
result.</SPAN></P>
		<H2 id="heading22"><SPAN>Local environments</SPAN></H2>
		<P><SPAN>Lambda expressions parse their bodies by creating a new parser, a 
LocalEnvironmentParser, which contains a pointer to the parser for the parent 
environment (or namespace). Its Parse method checks whether the expression is 
the name of a local variable in the environment. If so, it returns its 
associated LocalVariable expression object. Otherwise, it calls the parent 
parser's Parse method.</SPAN></P>
		<H2 id="heading23"><A title="External web link to " href=""><A><SPAN>Namespaces</SPAN></A></A></H2>
		<P><SPAN>Namespaces are parsers that handle name resolution for global variables 
and constants. The are instances of the abstract class NamespaceBase, a subclass 
of parser. All namespaces implement the following methods: </SPAN></P>
		<UL>
			<LI>
				<SPAN>Expression Lookup(Symbol name, bool searchImports, bool create, bool 
  includePrivate)</SPAN><BR>
				<SPAN>Returns the GlobalVariable object associated 
  with </SPAN><SPAN style="FONT-STYLE: italic">name</SPAN><SPAN>, or null if 
  none can be found. If </SPAN><SPAN style="FONT-STYLE: italic">name</SPAN><SPAN> isn't a bound in the namespace 
  and </SPAN><SPAN style="FONT-STYLE: italic">searchImports</SPAN><SPAN> is 
  true, the exports of each namespace in its import list will be also searched. 
  If </SPAN><SPAN style="FONT-STYLE: italic">includePrivate</SPAN><SPAN> is 
  false, and the binding found is not exported, then Lookup will return null, 
  even if a binding is found. Finally, if </SPAN><SPAN style="FONT-STYLE: italic">create</SPAN><SPAN> is true, a new, private 
  (unexported) binding is created in the namespace and returned when no binding 
  is found. It is illegal to call Lookup with </SPAN><SPAN style="FONT-STYLE: italic">create</SPAN><SPAN> true and </SPAN><SPAN style="FONT-STYLE: italic">includePrivate</SPAN><SPAN> false.</SPAN><BR>
			<LI>
				<SPAN>void Import(NamespaceBase ns)</SPAN><BR>
				<SPAN>Adds </SPAN><SPAN style="FONT-STYLE: italic">ns </SPAN><SPAN>to the namespace's list of imported 
  namespaces.</SPAN><BR>
			<LI>
				<SPAN>void Export(Symbol name)</SPAN><BR>
				<SPAN>Adds </SPAN><SPAN style="FONT-STYLE: italic">name </SPAN><SPAN>to the namespace's set of 
  imported symbols.</SPAN><BR>
			<LI>
				<SPAN>void Define(string name, object value)</SPAN><BR>
				<SPAN>void 
  Define(string name, object value, string documentation)</SPAN><BR>
				<SPAN>Adds 
  or mutates a binding to the namespace with the specified </SPAN><SPAN style="FONT-STYLE: italic">name</SPAN><SPAN>, </SPAN><SPAN style="FONT-STYLE: italic">value</SPAN><SPAN>, and optional </SPAN><SPAN style="FONT-STYLE: italic">documentation</SPAN><SPAN> string. The binding is 
  also marked as a constant and exported from the package. This is intended for 
  use at system startup time or DLL load time to allow C# code to add bindings 
  to packages.</SPAN><BR>
			<LI>
				<SPAN>object CheckBinding(object name)</SPAN><BR>
				<SPAN>Checks the 
  namespace for a binding with the specified </SPAN><SPAN style="FONT-STYLE: italic">name</SPAN><SPAN>, which can be either a symbol or 
  a string. It returns the value of the binding if one is found, or null, if the 
  value is unbound in the namespace. This is mostly used by the 
  editor.</SPAN><BR>
			<LI>
				<SPAN>object CheckFBinding(object name)</SPAN><BR>
				<SPAN>Same, but returns 
  null unless the binding's value is a procedure. This is mostly used by the 
  editor to implement arglist-on-space, etc. </SPAN></LI></UL>
		<P><SPAN>The Namespace class also exports the following static 
members:</SPAN></P>
		<UL>
			<LI>
				<SPAN>RootNamespace</SPAN><BR>
				<SPAN>The root namespace, which contains the 
  basic definitions of the core language. </SPAN>
			<LI>
				<SPAN>UserNamespace</SPAN><BR>
				<SPAN>The default namespace used by the user 
  </SPAN>
			<LI>
				<SPAN>CurrentNamespace</SPAN><BR>
				<SPAN>A property which returns the 
  current namespace in which code is evaluated. CurrentNamespace simply returns 
  the value of currentNamespaceFluid. </SPAN>
			<LI>
				<SPAN>currentNamespaceFluid</SPAN><BR>
				<SPAN>The fluid which holds the 
  current namespace. Rebind this to temporarily change the current namespace. 
  </SPAN>
			<LI>
				<SPAN>public static void SetNamespace(NamespaceBase 
  ns)</SPAN><BR>
				<SPAN>Sets CurrentNamespace to ns and signals 
  CurrentNamespaceChanged. Yes, I know this should be a set method of 
  CurrentNamespace, but the macro processor doesn't grok set methods. </SPAN>
			<LI>
				<SPAN>public static event VoidThunk 
  CurrentNamespaceChanged</SPAN><BR>
				<SPAN>Called when the current namespace is 
  changed using namespace!. This is mostly to allow the editor to track what 
  packages are associated with what files and editor windows, but might be of 
  other uses. </SPAN></LI></UL>
		<P><SPAN>Normal namespaces containing user code are of type Meta.Namespace. 
However, there are also specialized namespace classes.</SPAN></P>
		<H3 id="heading24"><SPAN>Meta.NativeNamespace</SPAN></H3>
		<P><SPAN>Implements name resolution for native CLR types. The built-in native 
namespaces in the root namespace are System, Microsoft, and Meta, but you can 
create your own if you need to access CLR namespaces outside the System and Meta 
hierarchies.</SPAN></P>
		<P><SPAN>When a NativeNamespace looks up a name, it first scans its cached 
bindings and returns the cached binding, if one is found. If not, it checks for 
a type with the same name. If not type is found, it returns null unless the 
</SPAN><SPAN style="FONT-STYLE: italic">create</SPAN><SPAN> argument is true. 
When </SPAN><SPAN style="FONT-STYLE: italic">create</SPAN><SPAN> is true, and no 
type can be found with the specified name, it create a new NativeNamespace whose 
name is the current namespace's name dot the name being looked up.</SPAN></P>
		<H3 id="heading25"><SPAN>Meta.Package</SPAN></H3>
		<P><SPAN>Packages are subclasses of Namespace (the "normal" namespace type), 
which inherit most of their behavior from the base class. The only difference is 
that before calling the base class, Packages check to see if they're loaded, and 
if not, load themselves from the pathname specified in their constructor. 
Package loading is thread-safe. When the package source file is a DLL, the 
system calls its </SPAN><A title="External web link to file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#DLL_loading"
				href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#DLL_loading"><A href="file:///C:/Program Files/Northwestern University/Meta/Help/Implementation notes.htm#DLL_loading"><SPAN style="TEXT-DECORATION: underline">Load method</SPAN></A></A><SPAN>, if any.</SPAN></P>
		<P><SPAN>Packages include two additional methods:</SPAN></P>
		<UL>
			<LI>
				<SPAN>public string AuxilliaryFilePath(string 
  name)</SPAN><BR>
				<SPAN>Prepends </SPAN><SPAN style="FONT-STYLE: italic">name</SPAN><SPAN> with the directory name of the 
  package's source file and returns it. </SPAN>
			<LI>
				<SPAN>public void LoadAssembly(string name)</SPAN><BR>
				<SPAN>Loads an 
  assembly named name from the same directory as the package's source file. That 
  is, it does Assembly.LoadFrom(AuxilliaryFilePath(name)). </SPAN></LI></UL>
		<H3 id="heading26"><SPAN>Meta.PackageDirectory</SPAN></H3>
		<P><SPAN>Like NativeNamespaces, PackageDirectories check an external source for 
their bindings, in this case a specified directory of the file system. When a 
name is looked up in the PackageDirectory, it checks for a file or directory 
with the specified name (plus either .meta or .dll) and creates a Package object 
with the file's pathname as its source file. When a directory is found, the 
source file path is </SPAN><SPAN style="FONT-STYLE: italic">packagedirectorypath</SPAN><SPAN>/</SPAN><SPAN style="FONT-STYLE: italic">name</SPAN><SPAN>/</SPAN><SPAN style="FONT-STYLE: italic">name</SPAN><SPAN>.meta (or .dll).</SPAN></P>
		<H2 id="heading27"><A title="External web link to " href=""><A><SPAN>DLL 
loading</SPAN></A></A></H2>
		<P><SPAN>When writing a package in C#, it is often desirable for the resulting 
DLL to be able to intern new definitions into a Meta package. This can be done 
by including a type with a method named Load and adding the following attribute 
to the assembly:</SPAN></P>
		<P><SPAN>[assembly: Meta.LoaderClassAttribute("</SPAN><SPAN style="FONT-STYLE: italic">Namespace</SPAN><SPAN>.</SPAN><SPAN style="FONT-STYLE: italic">TypeName</SPAN><SPAN>")]</SPAN></P>
		<P><SPAN>where </SPAN><SPAN style="FONT-STYLE: italic">Namespace</SPAN><SPAN>.</SPAN><SPAN style="FONT-STYLE: italic">Typename</SPAN><SPAN> is the fully-qualified type 
name of the class containing the Load method.</SPAN></P>
		<H1 id="heading28"><A title="External web link to " href=""><A><SPAN>Type 
lattice</SPAN></A></A><SPAN> and 
generic operations</SPAN></H1>
		<P><SPAN>The abstract classes Integer, Float, and Number are implemented as 
instances of Meta.PseudoType, a subclass of System.Type almost all of whose 
methods are blank (i.e. they do nothing, return false, or throw errors). Their 
only real methods are IsAssignableFrom() and IsInstanceOfType().</SPAN></P>
		<P><SPAN>There is also an abstract class, Meta.TypeLattice, which exports a 
static method: Type LUB(Type a, Type b), which computes the least upper bound of 
two types. This will eventually get used to implement type inference.</SPAN></P>
		<H2 id="heading29"><SPAN>Generic arithmetic</SPAN></H2>
		<P><SPAN>The generic arithmetic operations are fairly well optimized, although 
there's still room for improvement. For speed, n-ary arithmetic operations have 
separate methods for all Call methods and for Apply.</SPAN></P>
		<P><SPAN>All generic arithmetic operations basically have three 
cases:</SPAN></P>
		<UL>
			<LI>
				<SPAN style="FONT-WEIGHT: bold">All arguments are integral 
  types</SPAN><BR>
				<SPAN>All arguments are converted to System.Int32 and the 
  operation is performed. </SPAN>
			<LI>
				<SPAN style="FONT-WEIGHT: bold">All arguments are (scalar) numeric 
  types</SPAN><BR>
				<SPAN>All arguments are converted to System.Double and the 
  operation is performed. </SPAN>
			<LI>
				<SPAN style="FONT-WEIGHT: bold">At least one argument is 
  non-numeric</SPAN><BR>
				<SPAN>The procedure calls the associated VectorSpace 
  operation (this may involve some case analysis, e.g. to distinguish vector 
  from scalar multiplication) </SPAN></LI></UL>
		<H2 id="heading30"><SPAN>Vector spaces</SPAN></H2>
		<P><SPAN>Rather than supporting arbitrary overloading of the arithmetic 
procedures, Meta supports a general VectorSpace class. VectorSpace objects are 
really more generic function methods than they are actual instantiable types. 
For example, there is a class Meta.ColorVectorSpace, which holds the arithmetic 
implementations for class System.Drawing.Color because we can't add new methods 
after the fact to the built-in Color class.</SPAN></P>
		<P><SPAN>VectorSpaces support the following virtual methods:</SPAN></P>
		<UL>
			<LI>
				<SPAN>bool CheckEquality(object a, object b) </SPAN>
			<LI>
				<SPAN>object ScalarMultiple(double a, object v) </SPAN>
			<LI>
				<SPAN>object Sum(object a, object b) </SPAN>
			<LI>
				<SPAN>object Negation(object a) </SPAN>
			<LI>
				<SPAN>double Norm(object a) // static version is Magnitude </SPAN>
			<LI>
				<SPAN>object Unit(object a) // static version is UnitVector </SPAN>
			<LI>
				<SPAN>object Difference(object a, object b) </SPAN>
			<LI>
				<SPAN>object VectorProduct(object a, object b) </SPAN>
			<LI>
				<SPAN>object InnerProduct(object a, object b) </SPAN></LI></UL>
		<P><SPAN>The VectorSpace class also provides the following static 
methods:</SPAN></P>
		<UL>
			<LI>
				<SPAN>void Register(Type t, VectorSpace handler)</SPAN><BR>
				<SPAN>Declares 
  that </SPAN><SPAN style="FONT-STYLE: italic">handler</SPAN><SPAN> should be 
  used to perform arithmetic on objects of type </SPAN><SPAN style="FONT-STYLE: italic">t</SPAN><SPAN>. </SPAN>
			<LI>
				<SPAN>VectorSpace GetSpace(object vector, string 
  operation)</SPAN><BR>
				<SPAN>Returns the declared VectorSpace object for the 
  type of </SPAN><SPAN style="FONT-STYLE: italic">vector</SPAN><SPAN>, or calls 
  CantDo, if there's no registered handler for it.</SPAN><BR>
			<LI>
				<SPAN>static bool Equals(object a, object b)</SPAN><BR>
				<SPAN>Compares a to 
  b using the CheckEquality method of a's handler. We need this so we can 
  compare Points and PointFs.</SPAN><BR>
			<LI>
				<SPAN>static object Multiply(object a, object b)</SPAN><BR>
				<SPAN>Returns 
  the scalar or vector product of </SPAN><SPAN style="FONT-STYLE: italic">a</SPAN><SPAN> and </SPAN><SPAN style="FONT-STYLE: italic">b</SPAN><SPAN>, as appropriate.</SPAN><BR>
			<LI>
				<SPAN>static object ScalarMultiple(double a, object 
  v)</SPAN><BR>
				<SPAN>static object Add(object a, object 
  b)</SPAN><BR>
				<SPAN>static object Negate(object v)</SPAN><BR>
				<SPAN>static 
  double Magnitude(object v) // instance version is 
  Norm()</SPAN><BR>
				<SPAN>static object UnitVector(object v) // instance version 
  is Unit()</SPAN><BR>
				<SPAN>static object Subtract(object a, object 
  b)</SPAN><BR>
				<SPAN>static object VectorMultiply(object a, object 
  b)</SPAN><BR>
				<SPAN>static object InnerMultiply(object a, object 
  b)</SPAN><BR>
				<SPAN>Looks up the appropriate handler and calls its method. For 
  binary operations, the handler of the first vector argument is 
used.</SPAN><BR>
			<LI>
				<SPAN>void CantDo(string operation, object vector)</SPAN><BR>
				<SPAN>Throws 
  and ArgumentException with the message "Can't perform </SPAN><SPAN style="FONT-STYLE: italic">operation</SPAN><SPAN> on </SPAN><SPAN style="FONT-STYLE: italic">vector</SPAN><SPAN> with selected arguments" 
</SPAN>
			<LI>
				<SPAN>void CantDoNoArgs(string operation, object 
  vector)</SPAN><BR>
				<SPAN>Throws and ArgumentException with the message "Can't 
  perform </SPAN><SPAN style="FONT-STYLE: italic">operation</SPAN><SPAN> on 
  </SPAN><SPAN style="FONT-STYLE: italic">vector</SPAN><SPAN>" </SPAN></LI></UL>
		<P><SPAN>The VectorSpace class also exports a set of delegate types and 
registration functions to allow implementors of 3D graphics packages to extend 
Meta's built-in point, point-x, and point-y primitives:</SPAN></P>
		<UL>
			<LI>
				<SPAN>delegate bool TypePredicate(object x)</SPAN><BR>
				<SPAN>delegate 
  object Constructor3D(Single x, Single y, Single z)</SPAN><BR>
				<SPAN>delegate 
  object Constructor 4D(Single x, Single y, Single z, Single 
  w)</SPAN><BR>
				<SPAN>delegate Single Accessor(object x)</SPAN><BR>
			<LI>
				<SPAN>public static void Register3VectorOps(VectorSpace.TypePredicate p, 
  Constructor3D c, Accessor[] accessors)</SPAN><BR>
				<SPAN>Declares that the 
  built-in point primop should call c to make 3-vectors, that point? should call 
  p to test for 3-vectorness, and that point-x, point-y, and point-z should use 
  accessors[0], accessors[1], and accessors[2], respecitively. for member 
  access. </SPAN>
			<LI>
				<SPAN>public static void Register4VectorOps(VectorSpace.TypePredicate p, 
  Constructor4D c, Accessor[] accessors)</SPAN><BR>
				<SPAN>Same, but for 
  4-vectors. </SPAN></LI></UL>
		<H1 id="heading31"><A title="External web link to " href=""><A><SPAN>Bugs and 
misfeatures</SPAN></A></H1>
		<H2 id="heading32"><SPAN>Language semantics</SPAN></H2>
		<P><SPAN>Supporting the . notation for member access is very convenient but it 
does introduce some ambiguities:</SPAN></P>
		<UL>
			<LI>
				<SPAN>In a few cases a type's member is applicable to the type itself. 
  Hence, Object.ToString is ambiguous: it could mean either an unclosed wrapper 
  of one argument that computes the string form of an arbitrary object, or (less 
  likely) the method closed over the specific object "Object". Currently, the 
  system always considers it to be unclosed. </SPAN>
			<LI>
				<SPAN>This is fixed in version 1.3. Because namespaces are first-class in 
  Meta, but not in the CLR, typos are a problem in references to native 
  namespaces. In particular, one would like the (incorrect) 
  expression:</SPAN><BR>
				<BR>
				<SPAN>System.Drawing.PointG</SPAN><BR>
				<BR>
				<SPAN>to 
  generate an UndefinedVariableException. However, since the interpreter can't 
  prove there doesn't exist a namespace "System.Drawing.PointG", it presently 
  has to assume there is such a namespace. In theory, we could have the system 
  enumerate all types and check to see if one of them is in that namespace, but 
  (a) that would both be slow and would also break for namespaces defined in 
  DLLs that have not yet loaded. </SPAN></LI></UL>
		<H2 id="heading33"><SPAN>Plain old bugs</SPAN></H2>
		<UL>
			<LI>
				<SPAN>For reasons related to those above, apropos doesn't detect all 
  packages in package directories or all types in native namespaces. This will 
  get fixed at some point. </SPAN></LI></UL>
		<H2 id="heading34"><SPAN>Editor</SPAN></H2>
		<P><SPAN>The editor is built on top of the System.Windows.Forms.RichTextBox 
class, which appears to outcalll to the COM object for the old MFC 
RichTextEditCtl class. In any case, it has issues:</SPAN></P>
		<UL>
			<LI>
				<SPAN style="FONT-WEIGHT: bold">Undo support doesn't seem to 
  work.</SPAN><BR>
				<SPAN>Consequently, undo is implemented by periodically 
  converting the whole damn buffer into one big RTF string and pushing it on a 
  stack. This generally isn't a problem, but it becomes prohibitively slow when 
  the buffer contains images. Consequently, the editor quietly turns off undo 
  when the buffer goes over 50K. </SPAN>
			<LI>
				<SPAN style="FONT-WEIGHT: bold">The API doesn't allow insertion of 
  images.</SPAN><BR>
				<SPAN>Currently, writing of images to the listener window is 
  implemented by placing the image on the clipboard and doing a paste operation, 
  this is annoying both because it nukes the previous content of the clipboard 
  and because: </SPAN>
			<LI>
				<SPAN style="FONT-WEIGHT: bold">The Clipboard class, doesn't seem to 
  understand placing metafiles into the clipboard</SPAN><BR>
				<SPAN>So we have to 
  first convert vector graphics into Bitmap objects, place them in the clipboard 
  and then paste. This means that the RTF for the buffer contains uncompressed 
  bitmaps. Blech. </SPAN>
			<LI>
				<SPAN style="FONT-WEIGHT: bold">The API doesn't allow the scrollbar to be 
  locked.</SPAN><BR>
				<SPAN>This is finally fixed in version 1.3. This is the 
  single most common complaint about meta. The autoindent code has to read 
  attributes of text that sometimes appears off the screen. When this happens, 
  the RichTextBox rescrolls to put the text on the screen, even when window 
  update is locked. Consequently, even though we can prevent flashing from 
  gratuitous redrawing of the window, we can't prevent scrolling shifts that 
  seem inexplicable to the user. I've done a lot to mitigate it in this release, 
  so hopefully it won't bug people so much. </SPAN></LI></UL>
		<H2 id="heading35"><SPAN>Performance issues</SPAN></H2>
		<P><SPAN>Although it's surprising that Meta runs as fast as it does, this 
probably speaks more to the speed of today's hardware than anything else. Meta 
has virtually no optimizations in it. It is interpreted, all arithmetic is 
boxed, and it (presently) does no environment analysis to try to reduce memory 
usage.</SPAN></P>
		<H3 id="heading36"><SPAN>Editor</SPAN></H3>
		<P><SPAN>I've completely reimplemented the reindent logic so that it uses the 
underlying lisp reader and runs in one pass. So reindenting a function should 
only take 2-4 times as long as reading it. But it's it takes up to 300ms on 
large functions. I'm assuming that's the redraw code in RichTextBox, but I don't 
have a good way of checking.</SPAN></P>
		<H3 id="heading37"><SPAN>Debugging support</SPAN></H3>
		<P><SPAN>However, the biggest implementation problem for Meta is the fact that 
the CLR framework doesn't allow sufficient access to the run-time stack to write 
a conventional lisp-style debugger. In particular, the StackFrame class doesn't 
allow the user to determine what arguments were passed to the method represented 
by the frame. As a result, Meta has to maintain a shadow stack holding the 
procedures, argument lists, and environments of every Meta procedure (although 
it doesn't have to shadow all CLR methods being called). Although I don't have 
precise timing on this, I the interpreter spends 30-50% of its time on 
stack-related overhead.</SPAN></P>
		<P><SPAN>The EvalStack is a particular problem for making the interpreter 
multi-threaded, since it means the pointer to the stack object must be stored in 
thread-local storage. However, reading from thread-local storage requires 
~300nsec on my machine, so my initial implementation of multi-threading, which 
basically just involved making the EvalStack be a thread-static variable rather 
than a static variable, slowed the interpreter down by a factor of 3. Modifying 
the interpreter so that every method only read the variable once, dropped 
dropped it to a factor of 2. The current system passes the EvalStack as an 
explicit argument in every call in the interpreter, so the thread-local storage 
need only be read once. As a result, the current version of the interpreter is 
only about 7% slower than the last release, but I don't have detailed timings on 
how much of that is due to passing the stack around and how much is due to the 
addition of a trampoline to the Apply method of interpreted procedures to 
support tail recursion, which the previous version didn't support.</SPAN></P>
		<H3 id="heading38"><SPAN>Run-time type checking</SPAN></H3>
		<P><SPAN>The system also does a lot of casting, which is very slow in version 
1.1 of the .Net SDK. As far as I can tell, all cast and isinst instructions are 
compiled to an out-of-line call. If this is the same helper procedure that's in 
Rotor, it does a lot of case analysis and then crawls up the inheritance tree. 
This could be sped up enormously by special-casing value types, which can just 
be tested with a single comparison, since they don't support inheritance, and 
including a short array in the EECLASS object with all the class's direct 
ancestors. This would allow checks for class types to be reduced to a length 
check, an array reference, and a comparison. (Hint, hint...)</SPAN></P>
		<P><SPAN>Another optimization that would be useful would be if the CLR 
pre-allocated boxed versions of true and false so that boxing of Booleans would 
just require adding a constant. It would also allow testing of boxed Booleans 
using a pointer comparison. This is a relatively minor issue, 
however.</SPAN></P>
</BODY>
